package com.wa.util;


import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIONamespace;
import com.wa.constants.NameSpaceBeanNameConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author recharde.li@allchips.com
 * @version V1.0
 * @date 2020-05-26 16:27
 **/
//@EnableScheduling
//@Component("webSocketSessionManager")
public class WebSocketSessionManager {

    final static private Logger logger = LoggerFactory.getLogger(WebSocketSessionManager.class);

    /**
     * The lock protecting all mutators
     */
    static final transient ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();

    /**
     * 读锁
     */
    static final transient ReentrantReadWriteLock.ReadLock READ_LOCK = LOCK.readLock();

    /**
     * 写锁
     */
    static final transient ReentrantReadWriteLock.WriteLock WRITE_LOCK = LOCK.writeLock();

    /**
     * 本地缓存
     */
    private final static Map<String, HashSet<UUID>> CACHE = new ConcurrentHashMap<>();

    /**
     *
     */
    private final static Map<String, AtomicInteger> _DELETE_MAP = new ConcurrentHashMap<>();

    /**
     * 反向缓存
     */
    private final static Map<UUID, Object> MAP = new ConcurrentHashMap<>();

    @Resource(name = NameSpaceBeanNameConstant.BOSS)
    private SocketIONamespace bossSocketIONamespace;

    @Resource(name = NameSpaceBeanNameConstant.BOM)
    private SocketIONamespace bomSocketIONamespace;

    /**
     * 存入本地缓存
     *
     * @param userId         用户ID
     * @param sessionId      页面sessionID
     */
    public void saveClient(String userId, UUID sessionId) {
        HashSet<UUID> sessionIdClientCache = CACHE.get(userId);
        if (sessionIdClientCache == null) {
            try {
                WRITE_LOCK.lock();
                if ((sessionIdClientCache = CACHE.get(userId)) == null) {
                    sessionIdClientCache = new HashSet<>();
                    CACHE.put(userId, sessionIdClientCache);
                }
            } finally {
                WRITE_LOCK.unlock();
            }
        }
        sessionIdClientCache.add(sessionId);
        MAP.put(sessionId, userId);
    }

    /**
     * 根据用户ID获取所有通道信息
     *
     * @param userId
     * @return
     */
    public HashSet<UUID> getUserClient(String userId) {
        try {
            READ_LOCK.lock();
            return CACHE.get(userId);
        } finally {
            READ_LOCK.unlock();
        }
    }

    /**
     * 根据用户ID及页面sessionID删除页面链接信息
     *
     * @param sessionId
     */
    public void deleteSessionClient(UUID sessionId) {
        try {
            WRITE_LOCK.lock();
            Object key = MAP.remove(sessionId);
            CACHE.get(String.valueOf(key)).remove(sessionId);
        } catch (Exception e) {
        } finally {
            WRITE_LOCK.unlock();
        }
    }

    public Map<String, HashSet<UUID>> copyCache() {
        return CACHE;
    }

    @Scheduled(cron = "0 0/1 * * * ?") // 间隔60秒执行
    public void demonKiller() {
        try {
            for (Map.Entry<String, HashSet<UUID>> next : CACHE.entrySet()) {
                String cacheKey = next.getKey();
                int size = next.getValue().size();
                logger.info("用户cacheKey：{}当前建立了 {} 个长连接", cacheKey, size);
                if (size <= 0) {
                    try {
                        WRITE_LOCK.lock();
                        size = next.getValue().size();
                        if (size <= 0) {
                            if (null != _DELETE_MAP.get(cacheKey) && _DELETE_MAP.get(cacheKey).get() > 5) {  //大于5
                                _DELETE_MAP.remove(cacheKey);
                                CACHE.remove(cacheKey);
                            } else if (null != _DELETE_MAP.get(cacheKey) && _DELETE_MAP.get(cacheKey).get() <= 5) { //小于等于5
                                _DELETE_MAP.get(cacheKey).incrementAndGet();
                            } else if (null == _DELETE_MAP.get(cacheKey)) {  //等于空
                                _DELETE_MAP.put(cacheKey, new AtomicInteger(1));
                            }
                        }
                    } finally {
                        WRITE_LOCK.unlock();
                    }
                }
                for (UUID uuid : next.getValue()) {
                    try {
                        SocketIOClient client = bossSocketIONamespace.getClient(uuid);
                        client.sendEvent("test", "test");
                    } catch (Exception e) {
                    }
                    try {
                        SocketIOClient client = bomSocketIONamespace.getClient(uuid);
                        client.sendEvent("test", "test");
                    } catch (Exception e) {
                    }
                }
            }
        } catch (Exception e) {
        }
    }

}

